﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OmniKits
{
    using NullGuard;

    public delegate void StacklessEventHandler(object sender, StacklessEventArgs e);
#pragma warning disable 1591

    public sealed class StacklessEventArgs : EventArgs
    {
        private object _Sender;
        private StacklessEventHandler _NextHandler;

        private void CallNextHandlerInternal(object sender)
        {
            var handler = this._NextHandler;
            var last = (StacklessEventHandler)handler.GetInvocationList().Last();
            this._NextHandler = handler - last;

            last(sender, this);

            if (this._NextHandler != null)
                this.CallNextHandlerInternal(sender);
        }

        public void InvokeEventHandler(object sender, [AllowNull]StacklessEventHandler handler)
        {
            if (_NextHandler != null)
                throw new InvalidOperationException();

            if (handler == null) return;

            this._Sender = sender;
            this._NextHandler = handler;

            this.CallNextHandlerInternal(sender);

            this._Sender = null;
        }

        public static StacklessEventArgs Invoke(object sender, StacklessEventHandler handler)
        {
            var sea = new StacklessEventArgs();
            sea.InvokeEventHandler(sender, handler);
            return sea;
        }

        public bool Cancel()
        {
            if (this._NextHandler == null)
                return true;

            this._NextHandler = null;
            return false;
        }

        public void Invoke(object sender)
        {
            if (this._NextHandler == null)
                throw new InvalidOperationException();

            this.CallNextHandlerInternal(sender);
        }

        public void Invoke()
        {
            this.Invoke(this._Sender);
        }
    }
}
